"""
@author：yiwang
@file_name: __init__.py
@create date: 2023-11-17
@file_description：
"""

from apps.NGS_API.connector.db_common import *
from apps.NGS_API.common.common_time import *
from apps.NGS_API.common.db_table_config import *
import re

class operation_details(object):
    '''
        :param user_name
        :param ch_user
    '''
    def __init__(self,user_name,ch_user,resource_table):
        self.user_name = user_name
        self.ch_user = ch_user
        self.resource_table = resource_table
        self.operation ={
            "delete": "DELETE_OPERATION",
            "outstock": "OUTSTOCK_OPERATION",
            "add": "ADD_OPERATION",
            "put": "PUT_OPERATION",
            "query": "QUERY_OPERATION"
        }
    
    def query_base_infos(self,cols,table_name,id):
        query_infos_sql = '''
            SELECT 
                {cols}
            FROM 
                {table_name}
            WHERE
                id = {id}
        '''.format(
                cols = cols,
                table_name = table_name, 
                id = id
        )
        infos = query_info(query_infos_sql)
        return infos

    def get_add_infos(self,act_id,op_details=""):
        add_details = {
            "user_name": self.user_name,
            "ch_user": self.ch_user,
            "resource_table": self.resource_table,
            "act_id": act_id,
            "act_type":1,
            "code": 101,
            "op_time": get_current_time(),
            "op_details": op_details
        }
        return add_details

    def get_delete_infos(self,cols,id,act_id,**kwargs):
        ### Initialization ###
        op_details = ""
        ### SQL: query base infos ###
        tmp_infos = self.query_base_infos(
            cols =  cols,
            table_name = self.resource_table,
            id = id
        )
        ### SQL: delete details ###
        op_details = '''{prefix}:{operate_tag} DELETE {content} FROM {table_name}'''.format(
            prefix = self.user_name,
            operate_tag = self.operation["delete"],
            content = tmp_infos[0][0],
            table_name = self.resource_table
        )
        ### SQL: record details ####
        delete_details = {
            "user_name": self.user_name,
            "ch_user": self.ch_user,
            "resource_table": self.resource_table,
            "act_id": act_id,
            "act_type":2,
            "code": 102,
            "op_time": get_current_time(),
            "op_details": op_details,
            "reason_details": kwargs["reason_details"]
        }
        return delete_details
    
    def get_outstock_infos(self,cols,id,act_id,**kwargs):
        ### Initialization ###
        op_details = ""
        ### SQL: query base infos ###
        tmp_infos = self.query_base_infos(
            cols = cols,
            table_name = self.resource_table,
            id = id
        )
        ### SQL: delete details ###
        op_details = '''{prefix} {operate_tag}:OUTSTOCK {content} FROM {table_name}'''.format(
            prefix = self.user_name,
            operate_tag = self.operation["outstock"],
            content = tmp_infos[0][0],
            table_name = self.resource_table
        )
        outstock_details = {
            "user_name": self.user_name,
            "ch_user": self.ch_user,
            "resource_table": self.resource_table,
            "act_id": act_id,
            "act_type":5,
            "code": 105,
            "op_time": get_current_time(),
            "op_details": op_details,
            "reason_details": kwargs["reason_details"]
        }
        return outstock_details
    
    def create_update_details(self,id,cols,table_name,later_infos,**kwargs):
        ### STEP 0: create cols ###
        content = ""
        for _,values in cols.items():
            content = content + values.split('|')[0] + ","
        content = content.rstrip(",")
        ### STEP 1: query previous infos ### 
        base_infos = self.query_base_infos(
            cols=content,
            table_name=table_name,
            id=id
        )
        ### STEP 2: transform previous infos to dict ###
        previous_infos = {}
        keys = list(cols.keys())
        for i in range(0,len(base_infos[0])):
            previous_infos[keys[i]] = base_infos[0][i]
        ### STEP 3: compare previous and changed infos ###
        put_row_infos = ""
        for key,values in previous_infos.items():
            if values == later_infos[key]:
                pass
            elif values != later_infos[key]:
                put_row_infos = put_row_infos + '''{key}:{previous}=>{later}|'''.format(
                    key = key,
                    previous = previous_infos[key],
                    later = later_infos[key]
                )
        put_row_infos = put_row_infos.rstrip("|")
        ### STEP 4: create op details ###
        op_details = '''{user_name}:{operate_tag} {id} [ {put_details} ] from {table_name}'''.format(
            user_name = self.user_name,
            table_name = self.resource_table,
            operate_tag = self.operation["put"],
            put_details = put_row_infos,
            id = previous_infos[kwargs["tag"]]
        )
        return op_details
        
    def get_put_infos(self,cols,id,act_id,**kwargs):
        op_details = self.create_update_details(
            cols = cols,
            id = id,
            table_name = self.resource_table,
            later_infos = kwargs["later_infos"],
            reason_details = kwargs["reason_details"],
            tag=kwargs["tag"]
        )
        put_details = {
            "user_name": self.user_name,
            "ch_user": self.ch_user,
            "resource_table": self.resource_table,
            "act_id": act_id,
            "act_type": 3,
            "code": 103,
            "op_time": get_current_time(),
            "op_details": op_details,
            "reason_details":kwargs["reason_details"]
        }
        return put_details
    
    def get_query_infos(self,act_id,op_details):
        query_details = {
            "user_name": self.user_name,
            "ch_user": self.ch_user,
            "resource_table": self.resource_table,
            "act_id": act_id,
            "act_type":4,
            "code": 104,
            "op_time": get_current_time(),
            "op_details": op_details
        }
        return query_details

class operation_monitor(object):
    def __init__(self,table_name):
        self.table_name = table_name
        self.tags = {
            1: "ADD",
            2: "DEL",
            3: "PUT",
            4: "QUE",
            5: "OUT"
        }
        self.id = 0
        self.sql = '''
            INSERT INTO {table_name}
            (
                username,
                action_id,
                action_type,
                action_tag,
                operate_time,
                operate_details,
                check_user,
                tablename,
                reason_details
            ) VALUES (
                \"{user_name}\",
                \"{action_id}\",
                \"{action_type}\",
                \"{action_tag}\",
                \"{operate_time}\",
                \"{operate_details}\",
                \"{check_user}\",
                \"{resource_table}\",
                \"{reason_details}\"
            )
        '''
        
    """ record operation: record actions into log table """    
    def record_operation(self,details):
        ### STEP 1: record user actions to database ###
        record_sql = self.sql.format(
            table_name = self.table_name,
            user_name = details["user_name"],
            action_id = details["act_id"],
            action_type = details["act_type"],
            action_tag = self.tags[details["act_type"]],
            operate_time = details["op_time"],
            operate_details = details["op_details"],
            check_user = details["ch_user"],
            resource_table = details["resource_table"],
            reason_details = details["reason_details"]
        )
        ### STEP 2: add infos to database ###
        add_info(record_sql)

def Max(numbers):
    max = 0
    for num in numbers:
        if num > max:
            max = num
        else:
            pass
    return max

def get_user_operate_act_id(table_name):
    try:
        ### SQL: query extraction ID ###
        log_sql = '''
            SELECT 
                id,
                action_id
            FROM {table_name}
        '''.format(
            table_name = table_name
        )
        log_infos = query_info(log_sql)
        ### Extraction ID ###
        if not log_infos:
            return {"id":0,"act_id":"ACT992023033099000"}
        else:
            ids = [ action[0] for action in log_infos]
            max_id = Max(ids)
            act_ids = [ int(re.sub("[A-Za-z]","",action[1])) for action in log_infos ]
            max_act_id = Max(act_ids)
            return {"id":max_id,"act_id":"ACT" + str(max_act_id)}
    except Exception as e:
        print(e)
        
def record_user_operate(current_user,pm,cols:str,resource_table:str,record_table:str,ch_user:str,type_name:str,**kwargs):
    ### STEP 0: current user name ###
    cur_user = current_user.username
    ### STEP 1: create operation details ###
    pd = operation_details( 
            user_name = cur_user,
            ch_user = ch_user, 
            resource_table = resource_table
    )
    ### STEP 2: create action id ###
    act_ids = get_user_operate_act_id(table_name = record_table)
    ### STEP 3: return details of different types ###
    details = {}
    if type_name == "add":
        details = pd.get_add_infos(act_id = act_ids["act_id"])    
    elif type_name == "delete":
        details = pd.get_delete_infos(
            act_id = act_ids["act_id"],
            cols = cols,
            id = kwargs["id"],
            reason_details = kwargs["reason_details"]
        )
    elif type_name == "outstock":
        details = pd.get_outstock_infos(
            act_id = act_ids["act_id"],
            cols = cols,
            id = kwargs["id"],
            reason_details = kwargs["reason_details"]
        )
    elif type_name == "put":
        details = pd.get_put_infos(
            act_id = act_ids["act_id"],
            cols = cols,
            id = kwargs["id"],
            later_infos = kwargs["later_infos"],
            reason_details = kwargs["reason_details"],
            tag = kwargs["tag"]
        )
    elif type_name == "query":
        details = pd.get_query_infos(act_id = act_ids["act_id"])
    ### STEP 4: project monitor ###
    pm.record_operation(details = details)
    # return details